package controller

import (
	"container/heap"
	"fmt"
	"github.com/gin-gonic/gin"
	"gomvc/app/utils"
	"image"
	_ "image/png"
	"math"
	"os"
)

var Astar = new(astar)

// 全局配置
var cellSize = 0.001
var ratio = 1 / cellSize
var stepLen = 0.01

type astar struct{}

type Item struct {
	X int    `json:"x"`
	Y int    `json:"y"`
	G int    `json:"g"`
	H int    `json:"h"`
	P [2]int `json:"p"`
}

type Req struct {
	Start       [2]int    `json:"start"`
	Goal        [2]int    `json:"goal"`
	Barrier     [][2]int  `json:"barrier"`
	ChangePoint [2][2]int `json:"changePoint"`
}

type ReqFloat struct {
	Start       [2]float64 `json:"start"`
	Goal        [2]float64 `json:"goal"`
	Barrier     [][2]int   `json:"barrier"`
	ChangePoint [2][2]int  `json:"changePoint"`
}

// var wmap map[[2]float64]struct{} = allWhite()
// 一些全局变量
var wmapInt map[[2]int]struct{} = allWhiteInt()
var omap map[[2]float64]struct{}

// 线程安全的map
// var omap = new(sync.Map)

var omapInt map[[2]int]struct{}

var motions64 = [][2]float64{}
var motionsYn = [][2]float64{}
var allPath [][2]float64 = [][2]float64{}

// type rectangle struct {
// 	x1, y1, x2, y2 float64
// }

// var rectangleList []rectangle

// // 另一个
// var closeList [][2]float64
func Sa(start, goal [2]float64, c *gin.Context, runType int) (map[[2]float64][3]float64, [2]float64) {
	omap = map[[2]float64]struct{}{}

	omapInt = map[[2]int]struct{}{}
	num := 0
	pfloat := map[[2]float64][3]float64{
		{float64(start[0]), float64(start[1])}: {float64(start[0]), float64(start[1]), 0},
	}
	gfloat := map[[2]float64]float64{
		{float64(start[0]), float64(start[1])}: 0,
	}

	motions64 = [][2]float64{}
	motionsYn = [][2]float64{}
	// stepLen := 1.0
	//stepLen := 0.5
	// stepLen := 0.1
	if runType == 0 {
		motions64 = append(motions64, [2]float64{})
		for i := 0; i < 16; i++ {
			motions64 = append(motions64, [2]float64{stepLen * (math.Cos(float64(i) * math.Pi / 8)), stepLen * (math.Sin(float64(i) * math.Pi / 8))})
		}
	} else {
		// 32个方向
		for i := 0; i < 64; i++ {
			motions64 = append(motions64, [2]float64{stepLen * (math.Cos(float64(i) * math.Pi / 32)), stepLen * (math.Sin(float64(i) * math.Pi / 32))})
		}
	}
	openList := &PyHeap{}
	heap.Init(openList)
	heap.Push(openList, [4]float64{0, start[0], start[1]})

	for {
		num++
		minItem := heap.Pop(openList).([4]float64)
		angle := math.Atan2(goal[0]-minItem[1], goal[1]-minItem[2])
		motions64[0] = [2]float64{stepLen * (math.Cos(angle)), stepLen * (math.Sin(angle))}
		// range1 := 0.7
		//range1 := stepLen * 0.6

		//border1 := [2]float64{math.Ceil((minItem[1]-range1)*10) / 10, math.Ceil((minItem[2]-range1)*10) / 10}
		//border2 := [2]float64{math.Floor((minItem[1]+range1)*10) / 10, math.Floor((minItem[2]+range1)*10) / 10}
		//
		//for i := border1[0]; i <= border2[0]; i += 0.1 {
		//	for j := border1[1]; j <= border2[1]; j += 0.1 {
		//		omap[[2]float64{math.Round(i*10) / 10, math.Round(j*10) / 10}] = struct{}{}
		//	}
		//}

		// num是1000的倍数
		if num%50000 == 0 {
			fmt.Println("heap推出的点数:", num)
		}
		if math.Abs(minItem[1]-goal[0]) < 0.05 && math.Abs(minItem[2]-goal[1]) < 0.05 {
			//fmt.Println(minItem[1], goal[0])
			//fmt.Println(minItem[2], goal[1])
			fmt.Println("heap推出的点数:", num)
			if runType == 0 {
				createLine(pfloat, start, [2]float64{minItem[1], minItem[2]}, c, "root", 0, 0)
			}
			return pfloat, [2]float64{minItem[1], minItem[2]}
			// if runType == 0 {
			// c.JSON(200, gin.H{
			// 	"code": 0,
			// 	"msg":  "成功",
			// 	"data": gin.H{
			// 		"lines": path,
			// 		// "lines":    nil,
			// 		"openList": cyList,
			// 		"blocks":   list,
			// 	},
			// })
			// }

		}
		for idx, s_n := range getNeighborCircle(minItem) {

			if s_n[0] > 800 {
				continue
			} else {
				// newCost := gfloat[[2]float64{minItem[1], minItem[2]}] + 1.0
				newCost := gfloat[[2]float64{minItem[1], minItem[2]}] + stepLen
				// g没有这个点,赋大值
				_, ok := gfloat[s_n]
				if !ok {
					gfloat[s_n] = math.MaxInt
				}
				// 更新g并表明父关系
				if float64(newCost) < gfloat[s_n] {
					gfloat[s_n] = float64(newCost)
					pfloat[s_n] = [3]float64{float64(minItem[1]), float64(minItem[2]), float64(idx)}
					heap.Push(openList, [4]float64{float64(gfloat[s_n] + getHFloat(s_n, goal, runType)), float64(s_n[0]), float64(s_n[1]), float64(idx)})
				}
			}

		}
	}
}

func (*astar) BaseCh(c *gin.Context) {
	allPath = make([][2]float64, 0)
	// wmap = allWhite()
	var req *ReqFloat
	c.ShouldBind(&req)
	start := [2]float64{req.Start[0], req.Start[1]}
	goal := [2]float64{req.Goal[0], req.Goal[1]}

	// start := [2]float64{8.3041, 76.89}
	// goal := [2]float64{8.228, 78.2904}
	_, is := wmapInt[[2]int{int((start[1] + 180) * ratio), int((90 - start[0]) * ratio)}]
	_, is1 := wmapInt[[2]int{int((goal[1] + 180) * ratio), int((90 - goal[0]) * ratio)}]
	fmt.Println("起点:", is, "终点:", is1)
	if is || is1 {
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "成功",
			"data": gin.H{
				"lines":    nil,
				"openList": nil,
				"blocks":   nil,
			},
		})
		return
	}

	// 临时的
	// start := [2]float64{6.0054, 97.2729}
	// goal := [2]float64{3.64, 94.6801}
	fmt.Println("start:", start, "goal:", goal)
	// wmap = allWhite()
	Sa(start, goal, c, 0)
}

// func getGFloat(s, s_n [2]float64) float64 {
// 	// return utils.GetDistance(s[0], s[1], s_n[0], s_n[1])
// 	// 计算两点之间的距离
// 	return math.Sqrt(math.Pow(s[0]-s_n[0], 2) + math.Pow(s[1]-s_n[1], 2))
// }

func getHFloat(current, goal [2]float64, runType int) float64 {
	if runType == 0 {
		return math.Sqrt(math.Pow(current[0]-goal[0], 2) + math.Pow(current[1]-goal[1], 2))
	} else {
		return utils.GetDistance(current[0], current[1], goal[0], goal[1])
	}
	// return utils.GetDistance(current[0], current[1], goal[0], goal[1])
	// 计算直线距离
	// return math.Abs(current[0]-goal[0]) + math.Abs(current[1]-goal[1])
}

// 计算两坐标之间的实际距离

// 暂时的存白色可形式区域
// func allWhite() map[[2]float64]struct{} {
// 	// 创建一个map
// 	whiteMap := make(map[[2]float64]struct{})
// 	f, err := os.Open("C://Users//王春雨//Desktop//project//gomvc//public//image//HLT.png")
// 	if err != nil {
// 		panic(err)
// 	}
// 	defer f.Close()

//		img, _, err := image.Decode(f)
//		if err != nil {
//			panic(err)
//		}
//		for i := 0.0; i < float64(img.Bounds().Max.X); i = i + 0.1 {
//			for j := 0.0; j < float64(img.Bounds().Max.Y); j = j + 0.1 {
//				r, g, b, _ := img.At(int(i), int(j)).RGBA()
//				if r < 50000 && g < 50000 && b < 50000 {
//					lng := i/2 - 180
//					lat := -j/2 + 90
//					lng = math.Floor(lng*10) / 10
//					lat = math.Floor(lat*10) / 10
//					whiteMap[[2]float64{lat, lng}] = struct{}{}
//				}
//			}
//		}
//		return whiteMap
//	}
func allWhiteInt() map[[2]int]struct{} {
	return nil
	// return map[[2]int]struct{}{}
	whiteMap := make(map[[2]int]struct{}, 210000000)
	f1, _ := os.Open("./public/image/newhltrgb(14400_7200).png")
	defer f1.Close()
	// numW := 0
	// numB := 0
	// numE := 0
	img1, _, _ := image.Decode(f1)
	//for i := 0; i < img1.Bounds().Max.X; i++ {
	//	for j := 0; j < img1.Bounds().Max.Y; j++ {
	//		r, g, b, _ := img1.At(i, j).RGBA()
	//		// 如果不是纯白色
	//		if r != 65535 || g != 65535 || b != 65535 {
	//			whiteMap[[2]int{i, j}] = struct{}{}
	//		}
	//	}
	//}
	//for i := 14400; i < img1.Bounds().Max.X+14400; i++ {
	//	for j := 0; j < img1.Bounds().Max.Y; j++ {
	//		r, g, b, _ := img1.At(i-14400, j).RGBA()
	//		if r != 65535 || g != 65535 || b != 65535 {
	//			whiteMap[[2]int{i, j}] = struct{}{}
	//		}
	//	}
	//}

	//只有青岛附近
	//fmt.Println(img1.Bounds().Max.X, img1.Bounds().Max.Y)
	maxX, maxY := 360/cellSize, 180/cellSize

	for i := maxX * (298.0 / 360.0); i < maxX*(305.0/360.0); i++ {
		for j := maxY * (53.0 / 180.0); j < maxY*(58.0/180.0); j++ {
			//fmt.Println(i, j)
			r, g, b, _ := img1.At(int(i/25), int(j/25)).RGBA()
			// 如果不是纯白色
			//if r != 65535 || g != 65535 || b != 65535 {
			//	whiteMap[[2]int{i, j}] = struct{}{}
			//}
			//	如果是纯黑色
			if r == 0 && g == 0 && b == 0 {
				whiteMap[[2]int{int(i), int(j)}] = struct{}{}
			}
		}
	}
	//打印whiteMap的长度
	return whiteMap
}

type PyHeap [][4]float64

func (h PyHeap) Len() int      { return len(h) }
func (h PyHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h PyHeap) Less(i, j int) bool {
	return h[i][0] < h[j][0]
} // 小顶堆
func (h *PyHeap) Push(x interface{}) {
	*h = append(*h, x.([4]float64))
}
func (h *PyHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// var motions [][2]float64
var hcq [][2]int = [][2]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}

func getNeighborCircle(minItem [4]float64) [][2]float64 {
	// 判断minItem是否纬度在-10到10，经度在90到150
	// if minItem[1] > -10 && minItem[1] < 10 && minItem[2] > 90 && minItem[1] < 150 {
	// 	motions = motionsYn
	// } else {
	// 	motions = motions64
	// }

	// 判断点是否在rectangleList中的矩形内
	list := [][2]float64{}
	for _, u := range motions64 {
		lat := float64(minItem[1]) + u[1]
		lon := float64(minItem[2]) + u[0]
		// 这里的5相当于0.5度的自带缓冲区
		_, is := wmapInt[[2]int{int((lon + 180) * ratio), int((90 - lat) * ratio)}]
		//_, is1 := omap[[2]float64{math.Floor(lat*10) / 10, math.Floor(lon*10) / 10}]
		// _, is1 := omap.Load([2]float64{math.Floor(lat*10) / 10, math.Floor(lon*10) / 10})

		// is3 := false
		// for i := 0; i < 40; i++ {
		// 	lat1 := minItem[1] + (lat-minItem[1])*float64(i)/40
		// 	lon1 := minItem[2] + (lon-minItem[2])*float64(i)/40
		// 	_, is3 = wmapInt[[2]int{int((lon1 + 180) * 40), int((90 - lat1) * 40)}]
		// 	if is3 {
		// 		break
		// 	}
		// }

		//if !is && !is1 {
		//	is3 := isLandBetweenPoints(wmapInt, minItem[1], minItem[2], lat, lon)
		//
		//	if !is3 {
		//		is4 := false
		//		for _, u := range hcq {
		//			lat1 := lat + float64(u[1])*0.1
		//			lon1 := lon + float64(u[0])*0.1
		//			_, is4 = wmapInt[[2]int{int((lon1 + 180) * ratio), int((90 - lat1) * ratio)}]
		//			if is4 {
		//				break
		//			}
		//		}
		//		if !is4 {
		//			list = append(list, [2]float64{math.Floor(lat*10000) / 10000, math.Floor(lon*10000) / 10000})
		//		} else {
		//			list = append(list, [2]float64{999.0, 999.0})
		//		}
		//	} else {
		//		list = append(list, [2]float64{999.0, 999.0})
		//	}
		//} else {
		//	list = append(list, [2]float64{999.0, 999.0})
		//}

		if !is {
			list = append(list, [2]float64{math.Floor(lat*10000) / 10000, math.Floor(lon*10000) / 10000})
		} else {
			list = append(list, [2]float64{999.0, 999.0})
		}
	}
	return list
}

func createLine(p map[[2]float64][3]float64, start, goal [2]float64, c *gin.Context, root string, idx int, ldjl int) {

	// imgPath := [][2]int{}
	angle := -1.0
	s := [2]float64{goal[0], goal[1]}
	// s取p的最后一个元素
	path := [][2]float64{}

	for {
		item := p[s]
		s = [2]float64{item[0], item[1]}
		angle = p[s][2]
		if math.Abs(s[0]-start[0]) < 0.05 && math.Abs(s[1]-start[1]) < 0.05 {
			path = append(path, s)
			break
		}
		if item[2] != angle {
			path = append(path, s)
		}
	}
	allPath = append(allPath[:idx], append(path, allPath[idx:]...)...)
	//if ldjl == 0 {
	//	info := []any{}
	//	for i := 0; i < len(allPath); i++ {
	//		if i > 0 {
	//			dis := utils.GetDistance(allPath[i][0], allPath[i][1], allPath[i-1][0], allPath[i-1][1])
	//			// 判断两点连线与水平线的夹角
	//			angle := math.Atan2(allPath[i][1]-allPath[i-1][1], allPath[i][0]-allPath[i-1][0]) * 180 / math.Pi
	//			if math.Sqrt(dis) > 1500 && math.Abs(angle) < 120 && math.Abs(angle) > 60 {
	//				info = append(info, []any{allPath[i][0], allPath[i][1], allPath[i-1][0], allPath[i-1][1], i})
	//				// ppp, ggg := Sa([2]float64{allPath[i][0], allPath[i][1]}, [2]float64{allPath[i-1][0], allPath[i-1][1]}, c, 1)
	//				// createLine(ppp, [2]float64{allPath[i][0], allPath[i][1]}, ggg, c, "1", i, -1)
	//			}
	//		}
	//	}
	//	// fmt.Println("info", info, len(info))
	//	if len(info) == 1 {
	//		ppp, ggg := Sa([2]float64{info[0].([]any)[0].(float64), info[0].([]any)[1].(float64)}, [2]float64{info[0].([]any)[2].(float64), info[0].([]any)[3].(float64)}, c, 1)
	//		createLine(ppp, [2]float64{info[0].([]any)[0].(float64), info[0].([]any)[1].(float64)}, ggg, c, "1", info[0].([]any)[4].(int), -1)
	//	}
	//}
	if root == "root" {
		c.JSON(200, gin.H{
			"code": 0,
			"msg":  "成功",
			"data": gin.H{
				"lines": path,
				"all":   allPath,
			},
		})
	}
	// return path
}

// func isLandBetweenPoints(m map[[2]int]struct{}, lat1, long1, lat2, long2 float64) bool {
// 	// 将经纬度转换为网格坐标
// 	x1 := int((long1 + 180.0) / 360.0 * 14400.0)
// 	y1 := int((90.0 - lat1) / 180.0 * 7200.0)
// 	x2 := int((long2 + 180.0) / 360.0 * 14400.0)
// 	y2 := int((90.0 - lat2) / 180.0 * 7200.0)

// 	// 判断连线是否经过陆地
// 	dx := Abs(x2 - x1)
// 	dy := -Abs(y2 - y1)
// 	sx := 1
// 	if x1 > x2 {
// 		sx = -1
// 	}
// 	sy := 1
// 	if y1 > y2 {
// 		sy = -1
// 	}
// 	err := dx + dy
// 	for {
// 		if _, ok := m[[2]int{x1, y1}]; ok {
// 			// 网格坐标对应的位置是陆地
// 			return true
// 		}
// 		if x1 == x2 && y1 == y2 {
// 			// 已经遍历完所有网格
// 			break
// 		}
// 		e2 := 2 * err
// 		if e2 >= dy {
// 			err += dy
// 			x1 += sx
// 		}
// 		if e2 <= dx {
// 			err += dx
// 			y1 += sy
// 		}
// 	}

// 	return false
// }

func isLandBetweenPoints(m map[[2]int]struct{}, lat1, long1, lat2, long2 float64) bool {
	// 将经纬度转换为网格坐标
	x1 := int((long1 + 180.0) / 360.0 * 14400.0)
	y1 := int((90.0 - lat1) / 180.0 * 7200.0)
	x2 := int((long2 + 180.0) / 360.0 * 14400.0)
	y2 := int((90.0 - lat2) / 180.0 * 7200.0)

	// 判断连线是否经过陆地
	dx := Abs(x2 - x1)
	dy := -Abs(y2 - y1)
	sx := 2 // step size for x
	if x1 > x2 {
		sx = -2
	}
	sy := 2 // step size for y
	if y1 > y2 {
		sy = -2
	}
	err := dx + dy
	for {
		if _, ok := m[[2]int{x1, y1}]; ok {
			// 网格坐标对应的位置是陆地
			return true
		}
		if Abs(x2-x1) < 2 && Abs(y2-y1) < 2 {
			break
		}
		e2 := 2 * err
		if e2 >= dy {
			err += dy
			x1 += sx
		}
		if e2 <= dx {
			err += dx
			y1 += sy
		}
	}

	return false
}

func Abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}
